package service

import (
	"errors"
	"fitness/go-admin/internal/model"
	"fitness/go-admin/internal/repository"
	wsManager "fitness/go-admin/pkg/websocket"
	"fmt"
	"time"

	"gorm.io/gorm"
)

// ChatService 客服聊天业务逻辑层
type ChatService struct {
	chatRepo             *repository.ChatRepository
	userRepo             repository.UserRepository
	wsManager            *wsManager.Manager
	sensitiveWordService SensitiveWordService
}

// NewChatService 创建客服聊天服务
func NewChatService(chatRepo *repository.ChatRepository, userRepo repository.UserRepository) *ChatService {
	return &ChatService{
		chatRepo:  chatRepo,
		userRepo:  userRepo,
		wsManager: wsManager.GetManager(),
	}
}

// SetSensitiveWordService 设置敏感词服务（可选依赖）
func (s *ChatService) SetSensitiveWordService(service SensitiveWordService) {
	s.sensitiveWordService = service
}

// ==================== 会话管理 ====================

// CreateSession 创建会话
func (s *ChatService) CreateSession(memberID uint, sessionType, title string) (*model.ChatSession, error) {
	// 验证用户是否存在
	user, err := s.userRepo.GetByID(memberID)
	if err != nil {
		return nil, errors.New("用户不存在")
	}
	if user.Status != 1 {
		return nil, errors.New("用户已被禁用")
	}

	// 生成默认标题
	if title == "" {
		if sessionType == "CUSTOMER_SERVICE" {
			title = "客服咨询"
		} else {
			title = "教练咨询"
		}
	}

	// 创建会话
	session := &model.ChatSession{
		MemberID: memberID,
		Type:     sessionType,
		Status:   "WAITING",
		Title:    title,
	}

	if err := s.chatRepo.CreateSession(session); err != nil {
		return nil, fmt.Errorf("创建会话失败: %v", err)
	}

	// 加载关联数据
	session, err = s.chatRepo.GetSessionByID(session.ID)
	if err != nil {
		return nil, err
	}

	// 通知在线客服有新会话
	s.notifyNewSession(session)

	return session, nil
}

// GetSession 获取会话详情
func (s *ChatService) GetSession(sessionID, userID uint) (*model.ChatSession, error) {
	session, err := s.chatRepo.GetSessionByID(sessionID)
	if err != nil {
		return nil, errors.New("会话不存在")
	}

	// 验证权限：只能查看自己相关的会话
	if session.MemberID != userID && (session.StaffID == nil || *session.StaffID != userID) {
		return nil, errors.New("无权访问此会话")
	}

	return session, nil
}

// GetUserSessions 获取用户的会话列表
func (s *ChatService) GetUserSessions(userID uint, status string, page, pageSize int) (*model.SessionListResp, error) {
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 || pageSize > 100 {
		pageSize = 20
	}

	sessions, total, err := s.chatRepo.GetUserSessions(userID, status, page, pageSize)
	if err != nil {
		return nil, fmt.Errorf("获取会话列表失败: %v", err)
	}

	// 转换为响应格式
	items := make([]model.SessionItem, 0, len(sessions))
	for _, session := range sessions {
		item := s.convertSessionToItem(&session)
		items = append(items, item)
	}

	return &model.SessionListResp{
		List:     items,
		Total:    total,
		Page:     page,
		PageSize: pageSize,
	}, nil
}

// GetWaitingSessions 获取等待中的会话（客服端使用）
func (s *ChatService) GetWaitingSessions() ([]model.SessionItem, error) {
	sessions, err := s.chatRepo.GetWaitingSessions()
	if err != nil {
		return nil, fmt.Errorf("获取等待会话失败: %v", err)
	}

	items := make([]model.SessionItem, 0, len(sessions))
	for _, session := range sessions {
		item := s.convertSessionToItem(&session)
		items = append(items, item)
	}

	return items, nil
}

// AssignSession 分配会话给客服
func (s *ChatService) AssignSession(sessionID, staffID uint) error {
	// 验证会话
	session, err := s.chatRepo.GetSessionByID(sessionID)
	if err != nil {
		return errors.New("会话不存在")
	}
	if session.Status != "WAITING" {
		return errors.New("只能分配等待中的会话")
	}

	// 验证客服
	staff, err := s.userRepo.GetByID(staffID)
	if err != nil {
		return errors.New("客服不存在")
	}
	// 验证角色（只有管理员和教练可以当客服）
	if staff.RoleID != 1 && staff.RoleID != 2 {
		return errors.New("该用户不是客服或教练")
	}

	// 分配客服
	if err := s.chatRepo.AssignStaff(sessionID, staffID); err != nil {
		return fmt.Errorf("分配客服失败: %v", err)
	}

	// 通知会员和客服
	session.StaffID = &staffID
	session.Status = "ACTIVE"
	s.notifySessionUpdate(session)

	// 发送系统消息
	systemMsg := fmt.Sprintf("%s 已接入会话", staff.Nickname)
	s.SendSystemMessage(sessionID, systemMsg)

	return nil
}

// CloseSession 关闭会话
func (s *ChatService) CloseSession(sessionID, userID uint, rating *int, comment string) error {
	// 验证会话
	session, err := s.chatRepo.GetSessionByID(sessionID)
	if err != nil {
		return errors.New("会话不存在")
	}

	// 验证权限
	if session.MemberID != userID && (session.StaffID == nil || *session.StaffID != userID) {
		return errors.New("无权关闭此会话")
	}

	if session.Status == "CLOSED" {
		return errors.New("会话已关闭")
	}

	// 关闭会话
	if err := s.chatRepo.CloseSession(sessionID, userID, rating, comment); err != nil {
		return fmt.Errorf("关闭会话失败: %v", err)
	}

	// 通知对方
	session.Status = "CLOSED"
	s.notifySessionUpdate(session)

	// 发送系统消息
	s.SendSystemMessage(sessionID, "会话已关闭")

	return nil
}

// ==================== 消息管理 ====================

// SendMessage 发送消息
func (s *ChatService) SendMessage(userID uint, req *model.SendMessageReq) (*model.ChatMessage, error) {
	// 验证消息内容（业务层验证）
	if err := s.ValidateMessageContent(req); err != nil {
		return nil, err
	}

	// 敏感词过滤（仅过滤文本消息）
	if req.MessageType == "TEXT" && s.sensitiveWordService != nil {
		filterResult := s.sensitiveWordService.FilterText(req.Content)

		// 如果检测到需要拒绝的敏感词
		if !filterResult.Passed {
			return nil, fmt.Errorf("消息包含敏感词，发送失败: %v", filterResult.HitWords)
		}

		// 使用过滤后的内容
		req.Content = filterResult.FilteredText

		// 如果有命中敏感词，记录日志
		if len(filterResult.HitWords) > 0 {
			fmt.Printf("[敏感词过滤] 用户 %d 发送的消息命中敏感词: %v (级别: %s)\n",
				userID, filterResult.HitWords, filterResult.HighestLevel)
		}
	}

	// 验证会话（改进错误处理）
	session, err := s.chatRepo.GetSessionByID(req.SessionID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("会话不存在")
		}
		return nil, errors.New("查询会话失败")
	}

	// 验证权限
	if session.MemberID != userID && (session.StaffID == nil || *session.StaffID != userID) {
		return nil, errors.New("无权在此会话发送消息")
	}

	// 验证会话状态
	if session.Status == "CLOSED" {
		return nil, errors.New("会话已关闭，无法发送消息")
	}

	// 自动分配客服（如果会话是等待状态且发送者是客服）
	if session.Status == "WAITING" && session.MemberID != userID {
		s.chatRepo.AssignStaff(req.SessionID, userID)
		session.StaffID = &userID
		session.Status = "ACTIVE"
	}

	// 判断发送者类型
	senderType := "MEMBER"
	if session.StaffID != nil && *session.StaffID == userID {
		senderType = "STAFF"
	}

	// 创建消息
	message := &model.ChatMessage{
		SessionID:   req.SessionID,
		SenderID:    &userID, // 转换为指针类型
		SenderType:  senderType,
		MessageType: req.MessageType,
		Content:     req.Content,
		FileURL:     req.FileURL,
		FileName:    req.FileName,
		FileSize:    req.FileSize,
		ImageWidth:  req.ImageWidth,
		ImageHeight: req.ImageHeight,
	}

	// 使用事务确保数据一致性（消息创建 + 会话更新 + 未读数增加）
	if err := s.chatRepo.CreateMessageWithTransaction(message); err != nil {
		return nil, fmt.Errorf("发送消息失败: %v", err)
	}

	// 加载发送者信息
	message, _ = s.chatRepo.GetMessageByID(message.ID)

	// 推送消息给对方
	s.notifyNewMessage(session, message)

	return message, nil
}

// SendSystemMessage 发送系统消息
func (s *ChatService) SendSystemMessage(sessionID uint, content string) error {
	message := &model.ChatMessage{
		SessionID:   sessionID,
		SenderID:    nil, // 系统消息，发送者为空
		SenderType:  "SYSTEM",
		MessageType: "SYSTEM",
		Content:     content,
	}

	// 使用事务确保数据一致性（消息创建 + 会话更新）
	if err := s.chatRepo.CreateMessageWithTransaction(message); err != nil {
		return err
	}

	// 推送系统消息
	session, _ := s.chatRepo.GetSessionByID(sessionID)
	s.notifyNewMessage(session, message)

	return nil
}

// GetMessages 获取消息列表
func (s *ChatService) GetMessages(sessionID, userID uint, page, pageSize int, beforeID uint) (*model.MessageListResp, error) {
	// 验证会话和权限
	session, err := s.chatRepo.GetSessionByID(sessionID)
	if err != nil {
		return nil, errors.New("会话不存在")
	}
	if session.MemberID != userID && (session.StaffID == nil || *session.StaffID != userID) {
		return nil, errors.New("无权查看此会话消息")
	}

	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 || pageSize > 100 {
		pageSize = 50
	}

	messages, total, err := s.chatRepo.GetSessionMessages(sessionID, page, pageSize, beforeID)
	if err != nil {
		return nil, fmt.Errorf("获取消息列表失败: %v", err)
	}

	// 转换为响应格式
	items := make([]model.MessageItem, 0, len(messages))
	for i := len(messages) - 1; i >= 0; i-- { // 倒序，使最新消息在最后
		message := &messages[i]
		item := s.convertMessageToItem(message)
		items = append(items, item)
	}

	hasMore := int64((page-1)*pageSize+len(messages)) < total

	return &model.MessageListResp{
		List:     items,
		Total:    total,
		Page:     page,
		PageSize: pageSize,
		HasMore:  hasMore,
	}, nil
}

// MarkMessagesAsRead 标记消息已读
func (s *ChatService) MarkMessagesAsRead(sessionID, userID uint, messageIDs []uint) error {
	// 验证会话和权限
	session, err := s.chatRepo.GetSessionByID(sessionID)
	if err != nil {
		return errors.New("会话不存在")
	}
	if session.MemberID != userID && (session.StaffID == nil || *session.StaffID != userID) {
		return errors.New("无权操作")
	}

	// 标记已读
	if err := s.chatRepo.MarkMessagesAsRead(messageIDs); err != nil {
		return fmt.Errorf("标记已读失败: %v", err)
	}

	// 清空未读数
	isStaff := session.StaffID != nil && *session.StaffID == userID
	s.chatRepo.ClearUnreadCount(sessionID, isStaff)

	// 推送已读通知
	s.notifyMessagesRead(session, messageIDs, userID)

	return nil
}

// GetUserUnreadCount 获取用户未读消息总数
func (s *ChatService) GetUserUnreadCount(userID uint) (int64, error) {
	return s.chatRepo.GetUserTotalUnreadCount(userID)
}

// ==================== WebSocket通知 ====================

// notifyNewSession 通知有新会话
func (s *ChatService) notifyNewSession(session *model.ChatSession) {
	// 通知所有在线的管理员和教练
	// 这里简化处理，实际应该查询所有管理员和教练的ID
	wsMsg := model.WSMessage{
		Type:      "NEW_SESSION",
		Data:      s.convertSessionToItem(session),
		Timestamp: time.Now(),
	}
	s.wsManager.BroadcastToAll(wsMsg)
}

// notifySessionUpdate 通知会话更新
func (s *ChatService) notifySessionUpdate(session *model.ChatSession) {
	wsMsg := model.WSMessage{
		Type:      model.WSMessageTypeSessionUpdate,
		Data:      s.convertSessionToItem(session),
		Timestamp: time.Now(),
	}

	// 通知会员
	s.wsManager.SendToUser(session.MemberID, wsMsg)

	// 通知客服
	if session.StaffID != nil {
		s.wsManager.SendToUser(*session.StaffID, wsMsg)
	}
}

// notifyNewMessage 通知新消息
func (s *ChatService) notifyNewMessage(session *model.ChatSession, message *model.ChatMessage) {
	wsMsg := model.WSMessage{
		Type:      model.WSMessageTypeNewMessage,
		Data:      s.convertMessageToItem(message),
		Timestamp: time.Now(),
	}

	// 发送给会话相关的用户
	recipients := []uint{session.MemberID}
	if session.StaffID != nil {
		recipients = append(recipients, *session.StaffID)
	}

	s.wsManager.SendToUsers(recipients, wsMsg)
}

// notifyMessagesRead 通知消息已读
func (s *ChatService) notifyMessagesRead(session *model.ChatSession, messageIDs []uint, readerID uint) {
	wsMsg := model.WSMessage{
		Type: model.WSMessageTypeRead,
		Data: model.WSReadData{
			SessionID:  session.ID,
			MessageIDs: messageIDs,
		},
		Timestamp: time.Now(),
	}

	// 通知对方
	if session.MemberID != readerID {
		s.wsManager.SendToUser(session.MemberID, wsMsg)
	}
	if session.StaffID != nil && *session.StaffID != readerID {
		s.wsManager.SendToUser(*session.StaffID, wsMsg)
	}
}

// NotifyTyping 通知正在输入
func (s *ChatService) NotifyTyping(sessionID, userID uint, username string, isTyping bool) error {
	session, err := s.chatRepo.GetSessionByID(sessionID)
	if err != nil {
		return errors.New("会话不存在")
	}

	msgType := model.WSMessageTypeTyping
	if !isTyping {
		msgType = model.WSMessageTypeStopTyping
	}

	wsMsg := model.WSMessage{
		Type: msgType,
		Data: model.WSTypingData{
			SessionID: sessionID,
			UserID:    userID,
			Username:  username,
		},
		Timestamp: time.Now(),
	}

	// 通知对方
	if session.MemberID != userID {
		s.wsManager.SendToUser(session.MemberID, wsMsg)
	}
	if session.StaffID != nil && *session.StaffID != userID {
		s.wsManager.SendToUser(*session.StaffID, wsMsg)
	}

	return nil
}

// ==================== 辅助方法 ====================

// convertSessionToItem 转换会话为列表项
func (s *ChatService) convertSessionToItem(session *model.ChatSession) model.SessionItem {
	item := model.SessionItem{
		ID:            session.ID,
		Type:          session.Type,
		Status:        session.Status,
		Title:         session.Title,
		MemberID:      session.MemberID,
		LastMessageAt: session.LastMessageAt,
		UnreadCount:   session.UnreadCount,
		CreatedAt:     session.CreatedAt,
	}

	if session.Member != nil {
		item.MemberName = session.Member.Nickname
		item.MemberAvatar = session.Member.Avatar
	}

	if session.StaffID != nil {
		item.StaffID = session.StaffID
		if session.Staff != nil {
			item.StaffName = session.Staff.Nickname
			item.StaffAvatar = session.Staff.Avatar
		}
	}

	if session.LastMessage != nil {
		item.LastMessage = session.LastMessage.Content
		item.LastMessageType = session.LastMessage.MessageType
	}

	return item
}

// convertMessageToItem 转换消息为列表项
func (s *ChatService) convertMessageToItem(message *model.ChatMessage) model.MessageItem {
	var senderID uint
	if message.SenderID != nil {
		senderID = *message.SenderID
	}

	item := model.MessageItem{
		ID:          message.ID,
		SessionID:   message.SessionID,
		SenderID:    senderID, // 解引用指针类型
		SenderType:  message.SenderType,
		MessageType: message.MessageType,
		Content:     message.Content,
		FileURL:     message.FileURL,
		FileName:    message.FileName,
		FileSize:    message.FileSize,
		ImageWidth:  message.ImageWidth,
		ImageHeight: message.ImageHeight,
		IsRead:      message.IsRead,
		IsRecalled:  message.IsRecalled,
		CreatedAt:   message.CreatedAt,
		ReadAt:      message.ReadAt,
	}

	if message.Sender != nil {
		item.SenderName = message.Sender.Nickname
		item.SenderAvatar = message.Sender.Avatar
	}

	return item
}
